#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <SPI.h>
#include <MFRC522.h>

//引脚定义
#define SS_PIN            10
#define RST_PIN           9
#define DFPLAYER_RX_PIN   7
#define DFPLAYER_TX_PIN   8

//debug用
#define DEBUG_FLAG

//判定用回数
#define COUNT_NUM        20

SoftwareSerial mySoftwareSerial(DFPLAYER_RX_PIN, DFPLAYER_TX_PIN);
DFRobotDFPlayerMini myDFPlayer;

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
  
}

//主控模式
const int WAIT_MODE = 0;        //等待模式
const int SINGLE_MODE = 1;   //单曲播放模式

//等待时间(ms)
const int WAIT_TIME_50 = 50;
const int WAIT_TIME_100 = 100;
const int WAIT_TIME_1000 = 1000;

//MFRC522（NFC）实例
MFRC522 mfrc522(SS_PIN, RST_PIN);

// MFRC522（NFC）状态变量
MFRC522::StatusCode status; 

//播放状态确认（0:停止播放，1：正在播放）
int isPlaying = 0;

//卡片信息
struct NfcData {
  byte mode=1;
  byte vol=20;
  byte folderNum=1;
  byte fileNum=1;
  byte folderfileNum=1;
};

NfcData cardData;

void setup() {
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);

  // 初始化
  //PIN_SET
  DFPlayerSet();

  //模式初始化
  cardData.mode = WAIT_MODE;
  delay(1000);
  // SPI串口初始化
  SPI.begin();

  // MFRC522实例初始化
  mfrc522.PCD_Init(); 
}

void loop() {
  mode_main();

  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
  delay(WAIT_TIME_50);
}
/****************/
/*   初始化程序  */
/****************/

// DFPlayer初始化
void DFPlayerSet(){
  myDFPlayer.begin(mySoftwareSerial);
  Serial.println(F("DFPlayer Mini online."));
}

/****************/
/*   主控程序    */
/****************/

void mode_main(){
  static long state = 0;
  getCadData();
  switch(cardData.mode){
    case WAIT_MODE:        //等待模式
          isPlaying = 0;
          break;
    case SINGLE_MODE:
          if(!isPlaying){
              myDFPlayer.playMp3Folder(cardData.fileNum);
              isPlaying = 1;
          }
          break;
  }
}

/****************/
/*    卡片读取   */
/****************/
void getCadData(){
  // NFC读取用数组变量（最大144byte + CRC用2byte）
  byte read_buffer[146];
  byte size = sizeof(read_buffer);

  if(cardData.mode == WAIT_MODE){
    if(!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()){
      return;
    }
  }
  status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(4, read_buffer, &size);
  // 状态确认
  if (status != MFRC522::STATUS_OK) {
    cardData.mode = WAIT_MODE;
    return;
  }
  cardData.mode = SINGLE_MODE;
  cardData.mode = read_buffer[0];
  cardData.vol = read_buffer[1];
  cardData.folderNum = read_buffer[2];
  cardData.fileNum = read_buffer[3];
  cardData.folderfileNum = read_buffer[4] + 1;
}
